package com.list88zhu.common.rxhttp.http;

import android.util.Log;

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import rx.Observable;
import rx.functions.Func1;
import rx.functions.Func2;

/**
 * projectName rxretrofit
 * date 2017/6/23
 * description com.example.administrator.rxjavaretrofitsample.http
 */

public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {

    private static final String TAG = "RetryWhenNetworkExcepti";

    //重新请求次数
    private int count = 3;
    //延迟时间
    private long delay = 3;
    //叠加延迟时间
    private long increaseDelay = 3;

    public RetryWhenNetworkException(){}

    public RetryWhenNetworkException(int count, long delay){
        this.count = count;
        this.delay = delay;
    }

    public RetryWhenNetworkException(int count, long delay, long increaseDelay) {
        this.count = count;
        this.delay = delay;
        this.increaseDelay = increaseDelay;
    }



    @Override
    public Observable<?> call(Observable<? extends Throwable> observable) {
        
        return observable.zipWith(Observable.range(1, count + 1), new Func2<Throwable, Integer, Wrapper>() {
            @Override
            public Wrapper call(Throwable throwable, Integer integer) {
                return new Wrapper(throwable, integer);
            }
        }).flatMap(new Func1<Wrapper, Observable<?>>() {
            @Override
            public Observable<?> call(Wrapper wrapper) {
                if((wrapper.throwable instanceof ConnectException
                    || wrapper.throwable instanceof SocketTimeoutException
                    || wrapper.throwable instanceof TimeoutException)
                    && wrapper.index < count + 1){
                    Log.i(TAG, "call: " + wrapper.index);
                    return Observable.timer(delay + (wrapper.index + 1) * increaseDelay, TimeUnit.SECONDS);
                }
                return Observable.error(wrapper.throwable);
            }
        });
    }

    private class Wrapper{
        private int index;
        private Throwable throwable;

        public Wrapper(Throwable throwable, int index){
            this.index = index;
            this.throwable = throwable;
        }
    }
}
